// 该文件用于创建整个应用的路由

// (1) vueRouer相当于router的构造函数，就跟Vuex.Store是store构造函数一样
import VueRouter from "vue-router";

import About from "../pages/About";
import Home from "../pages/Home";
import Message from "../pages/Message";
import News from "../pages/News";
import Detail from "../pages/Detail";

// 下面中间的一段代码是为了防止出现多次点击同一个路由出现的错误
let originPush = VueRouter.prototype.push;
let originReplace = VueRouter.prototype.replace;
//重写push/replace
//第一个参数：告诉原来的push方法，往哪里跳转（传递哪些参数）
//第二个参数：成功的回调
//第三个参数：失败的回调
//call/apply区别
//相同点：都可以调用函数一次，都可以篡改函数的上下文(this）一次‘
//不同点：call/apply传递参数：call传递参数用逗号隔开，apply方法执行，传递数组
VueRouter.prototype.push = function (location, resolve, reject) {
  if (resolve && reject) {
    originPush.call(this, location, resolve, reject);
  } else {
    originPush.call(
      this,
      location,
      () => {},
      () => {}
    );
  }
};
VueRouter.prototype.replace = function (location, resolve, reject) {
  if (resolve && reject) {
    originReplace.call(this, location, resolve, reject);
  } else {
    originReplace.call(
      this,
      location,
      () => {},
      () => {}
    );
  }
};

const router = new VueRouter({
  // (2) routes复数，存放所有路由
  routes: [
    {
      name: "about",
      path: "/about",
      component: About,
      meta:{title: '关于'}
    },
    {
      name: "home",
      path: "/home",
      component: Home,
      meta:{title: '主页'},
      // (3) 子路由不需要加/因为写子路由说明后面有地址要写，就给你加上了
      children: [
        {
          name: "message",
          // (4) 注意是component不是components，一个路由只对应一个组件。因此不是复数
          path: "message",
          component: Message,
          meta: { isAuth: true,title: '消息' },
          children: [
            {
              // (5) 当路由层级较多时，要写name属性，这样写地址的时候直接用name就行(必须得用to的对象形式)
              name: "detail",
              path: "detail/:id/:title",
              component: Detail,
              // (6) props给当前路由对应的组件传递参数

              // props的第一种写法，值为对象，对象中的所有数据都会以props的形式传给Detail组件
              // props:{ a:1, b:'hello'}

              // props的第二种写法，值为布尔值，若为真则会把该路由中的params参数，props的形式传给Detail组件
              // props:true

              // props的第三种写法，值为函数,接收还是用props
              // (7) 当属性的值为函数时就可以直接将属性变为函数,这就是简写形式
              // props:()=>{}
              /**
               * (8) 注意这里参数是给我$route参数的,后面用了连续解构赋值,为了不想写那么多层
               *     非常灵活,有了$route就可以任意拿属性,即可选择query还是params
               *     但是还是推荐第一种写法,好代码是简洁而且还要易懂,那样别人可能看不懂
               * (9) 注意: props只是为了接收参数时,更加简洁,和router-link发送参数不一样
               *     这里只是把参数拦截下来并用props的形式发给Detail
               * */
              props($route) {
                return { id: $route.query.id, title: $route.query.title };
              },
              // props({query:{id,title}}){
              //   return {id,title}
              // }
              // props({params:{id,title}}){
              //   return {id,title}
              // }
              meta:{title: '细节'}
            },
          ],
        },
        {
          name: "news",
          path: "news",
          component: News,
          meta: { isAuth: true,title: '新闻' },
        },
      ],
    },
  ],
});

/**
 * (1) 全局前置路由 ------- 在初始化的时候被调用(第一次)、路由切换之前被调用(第二次及以上)
 *     全局体现在任意一个路由都会触发
 *     前置体现在进入当前路由之前才会触发
 * @param to 去哪个路由
 * @param from 从哪个路由来
 * @param next 放行，类似于node.js中的中间件，在做完判断之后再调用
 * */
router.beforeEach((to, from, next) => {
  // to and from are both route objects. must call `next`.
  console.log('前置路由守卫',to, from);
  /**
   * 这里想设置 进入message组件和news组件时必须要本地缓存中的school为atguigu才行
   * (2) 既可以用to的name或path判断目标路由地址是否是被允许的
   *     也可以在meta属性(允许程序员自己加入的属性，元，碎片的，需要程序员来加)
   *     里加一个权限判断的属性，这样直接看这个属性就行了，这么判断更加专业，还简洁点
   * */ 
  // if (to.name === "message" || to.name === "news") {
  if (to.meta.isAuth) {
    if (localStorage.getItem("school") === "atguigu") {
      next();
    } else {
      alert("学校名不对，无权限查看！");
    }
  } else {
    next();
  }
});

/**
 * (3) 全局后置路由 ------- 在初始化的时候被调用(第一次)、路由切换之后被调用(第二次及以上)
 *     在这里面一般处理 在路由允许之后 的事情，善后处理吧
 * */ 
router.afterEach((to,from)=>{
   console.log('后置路由守卫',to,from);
   document.title = to.meta.title || '尚硅谷'
})

export default router;
